package cn.relx.basic.service.impl;

import cn.relx.basic.config.BussinessException;
import cn.relx.basic.constant.BaseConstans;
import cn.relx.basic.mapper.VerifyCodeMapper;
import cn.relx.basic.service.VerifyCodeService;
import cn.relx.basic.util.SendMsgUtil;
import cn.relx.basic.util.StrUtils;
import cn.relx.basic.util.VerifyCodeUtils;
import cn.relx.basic.vo.RegisterVo;
import cn.relx.user.domain.User;
import cn.relx.user.mapper.UserMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.concurrent.TimeUnit;

@Service
@Transactional(readOnly = true,propagation = Propagation.SUPPORTS)
public class VerifyCodeServiceImpl implements VerifyCodeService {
    @Autowired
    private VerifyCodeMapper verifyCodeMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private UserMapper userMapper;

    @Override
    public String graph(String key) {
        //生成随机数
        String complexRandomString = StrUtils.getComplexRandomString(4);
        //将key，随机数，3，分钟，存入redis中
        redisTemplate.opsForValue().set(key,complexRandomString,3, TimeUnit.MINUTES);
        return VerifyCodeUtils.VerifyCode(100,35,complexRandomString);
    }

    @Override
    public void smsCode(RegisterVo vo) {
        //获取手机号、图形验证码、图形验证码redis的key
        String phone = vo.getPhone();
        String imageCodeKey = vo.getImageCodeKey();
        String imageCodeValue = vo.getImageCodeValue();
        //判断手机号是否被注册，如果注册则提示已注册
        //根据电话查询用户
        User user = userMapper.findByPhone(phone);
        //如果用户信息不为空，说明此手机号已被注册，提示用户直接登录
        if(user != null){
            throw new BussinessException("账号已注册，请直接登录!");
        }
        if("register".equals(vo.getType())){
            //判断参数是否为空
            if(StringUtils.isEmpty(phone)
                    || StringUtils.isEmpty(imageCodeKey)
                    || StringUtils.isEmpty(imageCodeValue)) {
                throw new BussinessException("参数错误，请输入正确参数!");
            }
            String smsCodeKey = BaseConstans.VerifyCodeConstant.BUSINESS_REGISTER_PREFIX+ phone;
            imageCodeLogin(vo.getImageCodeKey(),vo.getImageCodeValue());
            smsCodePhone(smsCodeKey);
        } else if("binder".equals(vo.getType())){
            // 如果type等于binder那么就直接发送短信验证码
            // 1.使用业务键拼接手机号从Redis中获取手机验证码 binder:phone
            // 2.如果是注册直接发送短信验证码即可
            String smsCodeKey = BaseConstans.VerifyCodeConstant.BUSINESS_BINDER_PREFIX+ phone;
            smsCodePhone(smsCodeKey);
        }


    }

    private void smsCodePhone(String smsCodeKey) {
        //如果前面的验证都通过了，那么说明用户需要重新获取手机验证码，但是我们不能直接发送验证码，因为我们还需要进行业务逻辑处理
        //使用业务逻辑拼接手机号，从redis中直接获取手机验证码，register:phone

        Object smsCodeValueTmp = redisTemplate.opsForValue().get(smsCodeKey);
        //判断验证码是否为空，为空说明验证码已过期，那么就生成一个新的验证码
        String smsCode = "";//用于存放重新发送给用户的验证码
        if(smsCodeValueTmp == null){
            //redis中手机验证码为空，那么就重新生成一个新的验证码
            smsCode = StrUtils.getComplexRandomString(4);
        } else {
            //redis中存在手机验证码，我们需要判断是否超过了一分钟，防止恶意请求
            //code:时间戳  这是我们手机验证码在redis中的格式，我们通过截取:获取时间戳，判断时间是否超过一分钟
            String[] smsCodeValueArray = smsCodeValueTmp.toString().split(":");
            //获取redis中的时间戳
            Long odeTimeTmp = Long.valueOf(smsCodeValueArray[1]);
            //创建一个新的时间戳
            Long newTimeTmp = System.currentTimeMillis();
            //判断现在时间戳减去旧的时间戳，是否大于一分钟，如果小于，说明没有超过一分钟，那么提示用户
            if(newTimeTmp - odeTimeTmp <= 1*60*1000){
                throw new BussinessException("请一分钟之后尝试");
            }
            //如果redis中还存在验证码，并且超过了一分钟，那么使用之前的验证码重置验证码时间
            smsCode = smsCodeValueArray[0];
        }
        //设置手机验证码到redis中，不管是否是第一次获取手机验证码都直接设置到redis中，并设置过期时间为三分钟
        String smsCodeValue = smsCode + ":" + System.currentTimeMillis();
        redisTemplate.opsForValue().set(smsCodeKey,smsCodeValue,3, TimeUnit.MINUTES);
        //发送短信验证码

//        SendMsgUtil.sendMsg("18160197927","阿西吧！没短信了:" + smsCode);
        System.out.println("验证码是:" + smsCode);
    }

    private void imageCodeLogin(String imageCodeKey, String imageCodeValue) {
        //校验图形验证码在redis中是否存在以及是否正确
        //根据图形验证码key值从redis中获取图形验证码code
        Object imageTemCode = redisTemplate.opsForValue().get(imageCodeKey);
        //判断redis是否存在该key的图形验证码，如果没有，说明用户非正常方式访问，直接抛异常
        if(imageTemCode == null){
            throw new BussinessException("验证码为空，请输入验证码!");
        }
        //获取到图形验证码，需要判断前端传递的验证码与redis中存入的是否一致，如果不一致提示用户
        if(!imageTemCode.toString().equalsIgnoreCase(imageCodeValue)){
            throw new BussinessException("验证码错误，请输入正确的验证码!");
        }
    }
}
